package monitor

import (
	"context"
	"github.com/lishimeng/go-log"
	"github.com/tarm/serial"
	"time"
)

type Weight struct {
	Name       string
	Baud       int
	Connection *serial.Port
	ctx        context.Context
	buf        []byte
	handler    *Handler
	State      bool // 串口可用时为true
}

func New(name string, baud int, waitExit context.Context,
	onDataRaw func(name string, data WeightDataRaw),
	onData func(name string, data WeightData)) *Weight {
	var w = &Weight{
		Name: name,
		Baud: baud,
		ctx:  waitExit,
		buf:  make([]byte, 256),
	}

	h := NewHandler(256, func(data WeightDataRaw) {
		if onDataRaw != nil {
			onDataRaw(name, data)
		}
	})
	h.Listener = func(data WeightData) {
		if onData != nil {
			onData(name, data)
		}
	}

	w.handler = h
	return w
}

func (w *Weight) Start() (err error) {
	config := serial.Config{
		Name: w.Name,
		Baud: w.Baud,
	}
	log.Info("connect to %s[%d]", config.Name, config.Baud)

	w.Connection, err = serial.OpenPort(&config)
	if err != nil {
		return
	}
	log.Info("open weight[%s] success", config.Name)
	w.State = true

	if w.ctx != nil {
		go w._loop()
	}
	return
}

func (w *Weight) _loop() {

	log.Info("start weight[%s] processor", w.Name)
	for {
		select {
		case <-w.ctx.Done():
			return
		default:
			size, err := w.read()
			if err != nil {
				log.Info("the weight read fail")
				w.LostConn(err)
				return
			}
			if size > 0 {
				err = w.addPayload(size)
				if err != nil {
					log.Info("add payload fail")
					fail := w.Connection.Close()
					if fail != nil {
						log.Info("close weight[%s] failed: %s", w.Name, fail)
					}
					w.LostConn(err)
					return
				}
			} else {
				time.Sleep(2 * time.Millisecond)
			}
		}
	}
}

func (w *Weight) addPayload(size int) (err error) {
	err = w.handler.read(w.buf[:size])
	return
}

func (w *Weight) LostConn(err error) {

	log.Info("the weight[%s] lost connection", w.Name)
	log.Info(err)
	w.State = false
}

func (w *Weight) read() (size int, err error) {
	size, err = w.Connection.Read(w.buf)
	return
}
